# @Time : 2024-12-23 14:44
# @Author : Fioman 
# @Phone : 13149920693
"""
生产作业界面操作对应的viewmodel,和生产作业相关的操作都是在这个类中进行通信的
"""
import threading
import time

import cv2 as cv
import gevent
import keyboard
import numpy as np

import app_config
from app.camera_tool import CameraTool
from app.device_state import DeviceState
from common.exception_helper import error_handler_produce, keep_error
from common.file_dir_helper import (save_totalboard_error_image, create_dir_by_order,
                                    save_size_is_ok_image, save_calc_error_image,
                                    save_calc_ok_image, save_cut_line_image, save_first_cutline_image, open_dir)
from common.produce_logger import debug_produce
from db_tool.db_config import TableName
from db_tool.db_handler import DbHandler
from eap_control.eap_config import EapConfig
from params.camera_params import CameraParams
from personal_tool.data_result import DataResult
from personal_tool.enum_data import EqpStatus
from vision_process.calc_config import TotalboardResult, CutlineResult
from vision_process.image_process_1 import get_size_check_result_1p, get_boxes_1p, get_cutlines_1p
from vision_process.totalboard_check import check_totalboard_is_ok
from web_tool import send_to_web_handler
from web_tool.produce_data_model import ProduceDataType
from web_tool.send_to_web_handler import show_cutline_in_web

ds = DeviceState()
db = DbHandler()
cp = CameraParams()
ec = EapConfig()


class ProduceHandler:
    def __init__(self, camTool, cutPlc):
        self.camTool: CameraTool = camTool
        self.cutPlc = cutPlc
        self.startProduceLastClick = 0
        self.cutBoardLastClick = 0
        self.isFirstBoard = False
        self.waitCheckBoardSize = False
        self.sizeCheckOkBtnClick = False
        self.waitHandLabelInnerBoard = False
        self.boardSizeAdjustFlag = False  # 尺寸是否调整的标志位
        self.widthAdjustAfter = 0
        self.heightAdjustAfter = 0
        self.boardSizeList = []
        self.boardResList = []
        self.boardSizeAdjustFlag = False
        self.bigCutEdgeMm = 0
        self.smallCutEdgeMm = 0
        self.calcEndwith = "calc"
        self.orderIsLoaded = False
        self.edgePixList = [0, 0, 0, 0]
        app_config.workStopState = True
        self.produceListenerThread = threading.Thread(target=self.produce_listener, daemon=True)
        self.produceListenerThread.start()

    def produce_listener(self):
        try:
            debug_produce("1. 自动作业监听任务开启")
            imageFailedCount = 0
            self.sensorErrorCount = 0
            self.webModify = False
            self.waitBoardBack = False
            self.upBoard = None
            self.buzzerIsOpen = False
            self.isFirstBoard = True
            self.idleTimeStart = 0
            while app_config.isMainAlive:
                if app_config.workStopState:
                    gevent.sleep(0.5)
                    continue
                while self.webModify:
                    gevent.sleep(0.5)
                    # 如果有弹窗,并且消失了,就关闭蜂鸣器叫
                    continue
                # 如果打开了蜂鸣器,这里要去关闭他
                if self.buzzerIsOpen:
                    self.cutPlc.set_buzzer_open_or_close(False)
                # 如果设备被锁机,就一直在这里循环不进行作业
                if app_config.deviceLock:
                    gevent.sleep(0.5)
                    continue
                if self.waitBoardBack:
                    gevent.sleep(0.5)
                    continue
                result = self.cutPlc.get_allow_take_pic()
                if not result.state:
                    keep_error(result.info)
                    gevent.sleep(2)
                    continue
                if not result.data:
                    gevent.sleep(0.2)
                    idleTime = time.time() - self.idleTimeStart
                    if idleTime > 2 * 60 and ec.eapOnline:
                        ec.update_eap_status(EqpStatus.Idle)
                    result = self.cutPlc.set_allow_plc_work()
                    if not result.state:
                        keep_error(result.info)
                        break
                    continue
                debug_produce(f"id_{ds.workIndex} 收到拍照信号")
                self.idleTimeStart = time.time()  # 更新空闲开始时间,从这里开始记录
                ec.update_eap_status(EqpStatus.Run)
                resultImg = self.camTool.get_image_from_line_cam()
                if not resultImg.state:
                    self.lineImage = None
                    if imageFailedCount == 0:
                        debug_produce(f"id_{ds.workIndex} 相机获取图片失败一次,进行重拍:{resultImg.info}")
                        result = self.cutPlc.re_get_img()
                        if not result.state:
                            keep_error(result.info)
                            return
                        self.camTool.re_start_line_camera()
                        imageFailedCount += 1
                        continue
                    else:
                        debug_produce(f"id_{ds.workIndex} 相机获取失败2次,报警提示:r{resultImg.info}")
                        keep_error(resultImg.info)
                        return
                self.lineImage = resultImg.data
                debug_produce(f"id_{ds.workIndex} 获取图片OK")
                imageFailedCount = 0
                totalboardResult: TotalboardResult = check_totalboard_is_ok(self.lineImage)
                self.totalboardBox = totalboardResult.boxMaster
                self.totalboard = totalboardResult.totalboardGray
                self.totalboardOffset = totalboardResult.totalboardOffset
                if not totalboardResult.state:
                    debug_produce(f"id_{ds.workIndex} ,{totalboardResult.info}")
                    save_totalboard_error_image(ds.workIndex, self.lineImage,
                                                totalboardResult.totalboardColor)
                    # 如果不是首片,就告诉Plc打开弹窗报警
                    if not self.isFirstBoard:
                        self.cutPlc.set_buzzer_open_or_close(True)  # 打开蜂鸣器报警
                        self.buzzerIsOpen = True
                    send_to_web_handler.show_totalboard_error_in_web(totalboardResult.totalboardColor,
                                                                     totalboardResult.info)
                    self.webModify = True
                    self.totalboardIsOk = False
                    while self.webModify:
                        gevent.sleep(0.5)
                    self.cutPlc.set_buzzer_open_or_close(False)  # 关闭蜂鸣器报警
                    if not self.totalboardIsOk:
                        continue

                self.sensorErrorCount = 0

                # 首片的尺寸确认的逻辑
                if self.isFirstBoard:
                    resFirst, boardSizeList, boardResList, upBoard = get_size_check_result_1p(
                        self.lineImage, self.widthPix, self.heightPix, self.totalboard, self.totalboardBox)

                    self.upBoard = upBoard
                    if resFirst == "ok":
                        self.send_size_check_image_to_web(boardSizeList, boardResList)
                        self.waitCheckBoardSize = True
                        self.sizeCheckOkBtnClick = False
                        while self.waitCheckBoardSize:
                            if app_config.workStopState:
                                debug_produce("检测到 app_config.workStopState = True 退出自动作业")
                                break
                            if self.sizeCheckOkBtnClick:
                                self.waitCheckBoardSize = False
                            gevent.sleep(0.2)
                    else:
                        # 弹窗人工标注内板尺寸框,需要人工去标注内板尺寸
                        debug_produce(f"id_{ds.workIndex} 内框识别失败,弹窗提示人工标注")
                        labelSize = [int(self.widthPix / cp.sizeScale), int(self.heightPix / cp.sizeScale)]
                        labelSizeMm = [self.widthMm, self.heightMm]
                        send_to_web_handler.show_board_size_hand_label_in_web(self.upBoard, labelSize,
                                                                              labelSizeMm)
                        self.waitHandLabelInnerBoard = True
                        while self.waitHandLabelInnerBoard:
                            if app_config.workStopState:
                                debug_produce("检测到 app_config.workStopState = True 退出自动作业")
                                break
                            gevent.sleep(0.2)

                self.box1p = None
                getBoxRes, info, self.box1p = get_boxes_1p(self.lineImage, self.widthPix, self.heightPix,
                                                           self.totalboardBox, self.totalboard)

                if not getBoxRes:
                    # 识别失败,弹窗提示工人进行标注
                    self.webModify = True
                    if not self.isFirstBoard:
                        self.cutPlc.set_buzzer_open_or_close(True)
                        self.buzzerIsOpen = True
                    self.send_hand_boxes_1pin()
                    save_calc_error_image(ds.workIndex, self.lineImage, self.widthPix, self.heightPix)
                    continue
                else:
                    self.calcEndwith = "calc"
                    save_calc_ok_image(ds.workIndex, self.lineImage, self.widthPix, self.heightPix)

                self.cutLineRes: CutlineResult = get_cutlines_1p(self.lineImage, self.totalboardBox,
                                                                 self.box1p, self.totalboardOffset, self.edgePixList)

                debug_produce(self.cutLineRes.info)
                save_cut_line_image(ds.workIndex, self.cutLineRes.imgRes, self.widthPix, self.heightPix,
                                    endwith=self.calcEndwith)
                if self.isFirstBoard:
                    self.webModify = True
                    show_cutline_in_web(self.cutLineRes.imgRes, self.cutLineRes.info)
                    continue
                else:
                    result = self.cutPlc.write_board_info(self.cutLineRes)
                    if not result.state:
                        keep_error(result.info)
                        return
                    self.cutPlc.result_is_ok()
                    debug_produce(result.info)
                ds.workIndex += 1
                if ds.workIndex >= ds.indexMax:
                    ds.workIndex = 1
                newData = {
                    "workIndex": ds.workIndex,
                }
                db.update_data(TableName.workingInfos, {"key": "1"}, newData)
                ds.update_finished_val()
        except Exception as e:
            debug_produce(f"自动作业任务检测到异常: {e}")
            app_config.workStopState = True
            return

        debug_produce("自动作业任务结束")

    def start_produce_from_web(self):
        """"
        界面上点击了启动自动作业,双击的是自动作业的工单
        :return:
        """
        debug_produce("界面上点击了自动作业按钮")
        safeDuration = 10
        if self.startProduceLastClick == 0:
            self.startProduceLastClick = time.time()
        else:
            clickDurationToLast = time.time() - self.startProduceLastClick
            if clickDurationToLast < safeDuration:
                debug_produce(f"自动作业按钮距离上次点击在{safeDuration}秒内,认为是误点击,本次不做响应")
                return
            else:
                self.startProduceLastClick = time.time()
        if not self.orderIsLoaded:
            self.change_order_from_web(ds.orderUsedKey)
        app_config.workStopState = False
        # 2. 判断当前的设备状态,如果不是运行状态,要启动设备
        if not ds.cutPlcState.isOnline:
            debug_produce("上位机自动作业开启,分板机设备(CutPlc)不在线")
            # return DataResult("CutPlc不在线,开始作业失败")
        else:
            # if not ds.cutPlcState.isRun:
            #     result = self.cutPlc.start_cut_plc()
            #     if not result.state:
            #         keep_error(result.info)
            #         return
            # 保证plc是运行状态,然后设置可以拍照
            result = self.cutPlc.set_allow_plc_work()
            if not result.state:
                keep_error(result.info)
                return DataResult(result.info)
        return DataResult(state=True)

    @error_handler_produce
    def save_order_from_web(self, newOrder) -> DataResult:
        """
        界面上点击了保存工单
        :param newOrder: 工单数据
        :return:
        """
        result = DataResult()
        saveKey = newOrder["key"]
        query = {
            "key": saveKey
        }
        queryRes = db.get_data_one(TableName.orders, query)
        if queryRes.state:
            # 更新数据
            db.update_data(TableName.orders, query, newOrder.copy())
        else:
            # 当工单第一次的时候,插入批号和数量这些列表
            db.insert_data(TableName.orders, newOrder.copy())
        totalRes = db.get_data_list(TableName.orders)
        totalOrders = totalRes.data if totalRes.state else []
        # 这里不知道为啥插入之后,newData就读了一个名字是_id的属性,需要pop出来
        result.state = True
        result.data = [[newOrder], totalOrders]
        return result

    # 更换批号

    def reload_order(self, newOrder, isFirstBoard):
        """
        当前作业参数加载,自动作业开始的时候,或者切换工单的时候重新加载作业工单
        :param newOrder:
        :param isFirstBoard:
        :return:
        """

        """
            "key": "default",
            "orderId": "Test001",
            "width": 12.23,  # 内层尺寸
            "height": 14.56,  # 内层尺寸
            "unit": "mm",  # 英寸
            "firstEdge": 0,  # 第一刀留边宽度
            "secondEdge": 0,  # 第二刀留边宽度
            "thirdEdge": 0,  # 第三刀留边宽度
            "fourthEdge": 0,  # 第四刀留边宽度
            "calcWidth": 0,  # 识别宽
            "calcHeight": 0,  # 识别高
            "planCount": 100,  # 计划数量
            "finished": 0,  # 完成数量
        """
        # 加载当前的工单信息
        self.orderKey = newOrder.get("key", "default")
        self.orderId = newOrder.get("orderId", "default")
        self.unit = newOrder.get("unit", "mm")
        if self.unit == "inch":
            self.widthOrder = float(newOrder.get("width", 20.34) * 25.4)
            self.heightOrder = float(newOrder.get("height", 19.24) * 25.4)
            self.calcWidthFirst = float(newOrder.get("calcWidth", 1.0) * 25.4)
            self.calcHeightFirst = float(newOrder.get("calcHeight", 1.0) * 25.4)
        else:
            self.widthOrder = float(newOrder.get("width", 20.34))
            self.heightOrder = float(newOrder.get("height", 19.24))
            self.calcWidthFirst = float(newOrder.get("calcWidth", 1.0))
            self.calcHeightFirst = float(newOrder.get("calcHeight", 1.0))

        self.firstEdge = float(newOrder.get("firstEdge", 0))
        self.secondEdge = float(newOrder.get("secondEdge", 0))
        self.thirdEdge = float(newOrder.get("thirdEdge", 0))
        self.fourthEdge = float(newOrder.get("fourthEdge", 0))

        debug_produce(f"in reload_order(): {newOrder}")

        # 将尺寸信息转换为像素单位
        self.widthMm = self.widthOrder
        self.heightMm = self.heightOrder
        self.widthPix = int(self.widthMm * cp.mm2pix)
        self.heightPix = int(self.heightMm * cp.mm2pix)
        self.firstEdgePix = int(self.firstEdge * cp.mm2pix)
        self.secondEdgePix = int(self.secondEdge * cp.mm2pix)
        self.thirdEdgePix = int(self.thirdEdge * cp.mm2pix)
        self.fourthEdgePix = int(self.fourthEdge * cp.mm2pix)
        self.edgePixList = [self.firstEdgePix, self.secondEdgePix, self.thirdEdgePix, self.fourthEdgePix]

        self.isFirstBoard = isFirstBoard

        # 创建工单使用的图像目录
        create_dir_by_order(self.orderId)
        # 如果是首片,就证明是自动作业开始启动,这个时候要更新workindex里面的内容
        if self.orderKey != ds.orderUsedKey:
            newWorkingInfo = {
                "orderUsedKey": self.orderKey,  # 工作工单key
                "orderUsedId": self.orderId,  # 工作工单料号
                "workIndex": 1,  # 物料编号从1开始
                "finishedCount": 0,  # 已完成数量
            }
            db.update_data(TableName.workingInfos, {"key": "1"}, newWorkingInfo)
            ds.realod_working_info()

        self.orderIsLoaded = True

    def re_get_image(self):
        """
        传感器误差太大,自动重拍
        """
        self.cutPlc.re_get_img()
        self.webModify = False
        ds.workIndex += 1
        if ds.workIndex > ds.indexMax:
            ds.workIndex = 1
        newData = {
            "workIndex": ds.workIndex
        }
        db.update_data(TableName.workingInfos, {"key": "1"}, newData)
        return "ok"

    def board_back_from_web(self) -> DataResult:
        result = self.cutPlc.re_get_img()
        if not result.state:
            return result
        self.waitBoardBack = True
        self.webModify = False
        debug_produce(f"id_{ds.workIndex} 界面上点击了板回退,物料重新回退到拍照起点")
        return result

    def re_get_image_from_web(self):
        """
        界面上点击了重新拍照的逻辑
        :return:
        """
        debug_produce(f"id_{ds.workIndex} 界面上点击了重新拍照,进行重拍")
        if self.waitBoardBack:
            self.waitBoardBack = False
        else:
            result = self.cutPlc.re_get_img()
            if not result.state:
                return result

        self.webModify = False
        ds.workIndex += 1
        if ds.workIndex > ds.indexMax:
            ds.workIndex = 1
        newData = {
            "workIndex": ds.workIndex
        }
        db.update_data(TableName.workingInfos, {"key": "1"}, newData)
        return DataResult(state=True)

    def stop_produce_from_web(self):
        """
        停止自动作业
        """
        debug_produce(f"id_{ds.workIndex} 界面上点击了停止自动作业,自动作业任务停止")
        app_config.workStopState = True
        self.waitBoardBack = False
        self.webModify = False
        self.cutPlc.clear_total_signal()
        self.cutPlc.clear_allow_get_pic_state()
        return DataResult(state=True)

    def total_board_is_ok_from_web(self):
        """
        人工确认物料OK
        """
        debug_produce(f"id_{ds.workIndex} 界面上点击了人工确认物料OK,继续自动作业")
        self.totalboardIsOk = True
        self.webModify = False
        return DataResult(state=True)

    def send_size_check_image_to_web(self, sizeList, resList):
        self.boardSizeList = sizeList
        self.boardResList = resList
        self.sendIndex = 0
        image = self.boardResList[self.sendIndex]
        boardSize = self.boardSizeList[self.sendIndex]
        inputSize = (self.widthOrder, self.heightOrder)
        calcError = round(boardSize[0] - inputSize[0], 2), round(boardSize[1] - inputSize[1], 2)
        send_to_web_handler.show_board_size_check_in_web(image, boardSize, inputSize, calcError)

    @error_handler_produce
    def keep_ok_size_from_web(self) -> DataResult:
        """
        人工确认尺寸OK
        """
        debug_produce(f"id_{ds.workIndex} 界面上点击了人工确认尺寸OK,"
                      f"确认尺寸:{self.boardSizeList[self.sendIndex]}")
        imageKeep = self.boardResList[self.sendIndex]
        self.keep_calc_size()
        save_size_is_ok_image(ds.workIndex, imageKeep, self.widthPix, self.heightPix,
                              "calc")
        self.sizeCheckOkBtnClick = True
        return DataResult(state=True)

    def keep_calc_size(self):
        self.widthMm, self.heightMm = self.boardSizeList[self.sendIndex]
        self.calcWidthFirst = self.widthMm
        self.calcHeightFirst = self.heightMm
        self.widthPix, self.heightPix = int(self.widthMm * cp.mm2pix), int(self.heightMm * cp.mm2pix)
        newData = {
            "calcWidth": self.calcWidthFirst,
            "calcHeight": self.calcHeightFirst
        }
        db.update_data(TableName.orders, {"key": ds.orderUsedKey}, newData)
        send_to_web_handler.update_produce_model_in_web(ProduceDataType.workingOrder)

    def next_board_res_from_web(self) -> DataResult:
        """
        切换到下一个尺寸
        """
        self.sendIndex += 1
        if self.sendIndex >= len(self.boardSizeList):
            self.sendIndex = 0
        image = self.boardResList[self.sendIndex]
        boardSize = self.boardSizeList[self.sendIndex]
        inputSize = (self.widthOrder, self.heightOrder)
        calcError = round(boardSize[0] - inputSize[0], 2), round(boardSize[1] - inputSize[1], 2)
        send_to_web_handler.show_board_size_check_in_web(image, boardSize, inputSize, calcError)
        return DataResult(state=True)

    def last_board_res_from_web(self) -> DataResult:
        """
        切换到上一个尺寸
        """
        self.sendIndex -= 1
        if self.sendIndex < 0:
            self.sendIndex = len(self.boardSizeList) - 1
        image = self.boardResList[self.sendIndex]
        boardSize = self.boardSizeList[self.sendIndex]
        inputSize = (self.widthOrder, self.heightOrder)
        calcError = round(boardSize[0] - inputSize[0], 2), round(boardSize[1] - inputSize[1], 2)
        send_to_web_handler.show_board_size_check_in_web(image, boardSize, inputSize, calcError)
        return DataResult(state=True)

    def hand_inner_board_size_from_web(self):
        """
        人工标注尺寸,弹窗提示内存尺寸标注框
        """
        debug_produce(f"id_{ds.workIndex} 界面上点击了人工标注尺寸,标注尺寸:"
                      f"{self.boardSizeList[self.sendIndex]}")
        boardSend = self.upBoard
        labelSize = [int(self.widthPix / cp.sizeScale), int(self.heightPix / cp.sizeScale)]
        labelSizeMm = [self.widthMm, self.heightMm]
        send_to_web_handler.show_board_size_hand_label_in_web(boardSend, labelSize, labelSizeMm)

    def inner_board_size_change_from_web(self, widthAdjust, heightAdjust):
        """
        界面上点击了调整尺寸确认的逻辑,首片调整尺寸确认
        """
        self.boardSizeAdjustFlag = True  # 是否调整了尺寸
        widthOrignal, heightOriginal = self.widthMm, self.heightMm
        widthOrignal += widthAdjust
        heightOriginal += heightAdjust

        self.widthAdjustAfter = widthOrignal
        self.heightAdjustAfter = heightOriginal

        boardSend = self.upBoard
        labelSize = [self.widthAdjustAfter * cp.mm2pix // cp.sizeScale,
                     self.heightAdjustAfter * cp.mm2pix // cp.sizeScale]
        labelSizeMm = [self.widthAdjustAfter, self.heightAdjustAfter]
        send_to_web_handler.show_board_size_hand_label_in_web(boardSend, labelSize, labelSizeMm)

    def hand_inner_board_size_ok_from_web(self, leftTop, angle):
        """
        人工确认内板尺寸OK
        """
        debug_produce(f"id_{ds.workIndex} 界面上点击了人工确认内板尺寸OK,确认尺寸:{leftTop},{angle}")
        self.waitHandLabelInnerBoard = False
        self.waitCheckBoardSize = False
        if self.boardSizeAdjustFlag:
            self.widthMm = self.widthAdjustAfter
            self.heightMm = self.heightAdjustAfter
            self.boardSizeAdjustFlag = False
        if self.isFirstBoard:
            self.widthPix, self.heightPix = int(self.widthMm * cp.mm2pix), int(self.heightMm * cp.mm2pix)
            self.calcWidthFirst = self.widthMm
            self.calcHeightFirst = self.heightMm
            newData = {
                "calcWidth": self.calcWidthFirst,
                "calcHeight": self.calcHeightFirst
            }
            db.update_data(TableName.orders, {"key": ds.orderUsedKey}, newData)
            send_to_web_handler.update_produce_model_in_web(ProduceDataType.workingOrder)
        leftTop = [int(leftTop[0] * cp.sizeScale), int(leftTop[1] * cp.sizeScale)]
        upBoxPoints = self.get_box_rect_points(self.upBoard, leftTop, angle)
        keepImage = self.upBoard.copy()
        cv.drawContours(keepImage, [np.array(upBoxPoints)], -1,
                        (0, 255, 255), 3)
        save_size_is_ok_image(ds.workIndex, keepImage, self.widthPix, self.heightPix,
                              "handLabel")
        return DataResult(state=True)

    def get_box_rect_points(self, board, point, angle):
        """
        根据图像,以及左上角的点和角度获取标注的矩形
        :param board: 传递过来的整个物料框,矩形的左上角
        :param point: 最左边的点,angle,旋转角度
        :param angle:
        :return:
        """
        widthPix = int(self.widthAdjustAfter * cp.mm2pix) if self.boardSizeAdjustFlag else self.widthPix
        heightPix = int(self.heightAdjustAfter * cp.mm2pix) if self.boardSizeAdjustFlag else self.heightPix
        h, w = board.shape[:2]
        pointList = [[point[0] + widthPix, point[1]],
                     [point[0] + widthPix, point[1] + heightPix],
                     [point[0], point[1] + heightPix]]  # 矩形框的另外三个点
        newPoints = []  # 存放新的坐标点
        newPoints.append(point)
        for p in pointList:
            x1 = p[0]
            y1 = h - p[1]
            x2 = point[0]
            y2 = h - point[1]
            x = int((x1 - x2) * np.cos(angle * np.pi / 180.0) - (y1 - y2) * np.sin(angle * np.pi / 180.0) + x2)
            y = int((x1 - x2) * np.sin(angle * np.pi / 180.0) + (y1 - y2) * np.cos(angle * np.pi / 180.0) + y2)
            y = h - y
            newPoints.append([x, y])
        return newPoints

    def send_hand_boxes_1pin(self):
        """
        弹窗进行1拼板的标注
        :return:
        """
        image = self.totalboard
        labelSizePix = [int(self.widthPix / cp.sizeScale), int(self.heightPix / cp.sizeScale)]
        labelSizeMm = [self.widthMm, self.heightMm]
        send_to_web_handler.show_inner_board_hand_1pin(image, labelSizePix, labelSizeMm)

    def get_cutboard_size_and_center(self):
        """
        获取切割后尺寸和识别的中心点
        """
        cutRes = self.cutLineRes
        if cutRes:
            calcSize = [cutRes.calcWidth, cutRes.calcHeight]
            cutBoardSize = [cutRes.cutLen, cutRes.cutWidth]
            catchCenter01 = f"({cutRes.robotX01},{cutRes.robotY01},{cutRes.robotR01})"
            catchCenter02 = f"({cutRes.robotX02},{cutRes.robotY02},{cutRes.robotR02})"
            return calcSize, cutBoardSize, catchCenter01, catchCenter02
        else:
            return [0, 0], [0, 0], "(0,0,0)", "(0,0,0)"

    def cut_board_from_web(self, firstEdge, secondEdge, thirdEdge, fourthEdge):
        """
        界面上点击了切板
        :param firstEdge:
        :param secondEdge:
        :param thirdEdge:
        :param fourthEdge:
        :return:
        """
        debug_produce(f"id_{ds.workIndex} 点击了切板,第一刀留边宽度:{firstEdge}"
                      f"第二刀留边宽度:{secondEdge},第三刀留边宽度:{thirdEdge},第四刀留边宽度:{fourthEdge}")

        # 将切线图保存到首片当中去
        save_first_cutline_image(ds.workIndex, self.cutLineRes.imgRes, self.widthPix,
                                 self.heightPix)
        if self.isFirstBoard:
            self.firstEdge = firstEdge
            self.secondEdge = secondEdge

            self.thirdEdge = thirdEdge
            self.fourthEdge = fourthEdge
            self.firstEdgePix = int(self.firstEdge * cp.mm2pix)
            self.secondEdgePix = int(self.secondEdge * cp.mm2pix)
            self.thirdEdgePix = int(self.thirdEdge * cp.mm2pix)
            self.fourthEdgePix = int(self.fourthEdge * cp.mm2pix)
            self.edgePixList = [self.firstEdgePix, self.secondEdgePix, self.thirdEdgePix, self.fourthEdgePix]
            # 更新首片切线图信息
            firstCalcError = (round(self.calcWidthFirst - self.widthOrder, 2),
                              round(self.calcHeightFirst - self.heightOrder, 2))
            # 获取切割后尺寸和识别的中心点
            _, cutboardSize, catchCenter01, catchCenter02 = self.get_cutboard_size_and_center()
            send_to_web_handler.show_first_cutline_in_web(self.cutLineRes.imgRes, firstCalcError,
                                                          cutboardSize, catchCenter01, catchCenter02)
            newData = {
                "firstEdge": self.firstEdge,
                "secondEdge": self.secondEdge,
                "thirdEdge": self.thirdEdge,
                "fourthEdge": self.fourthEdge
            }
            db.update_data(TableName.orders, {"key": ds.orderUsedKey}, newData)
            send_to_web_handler.update_produce_model_in_web(ProduceDataType.workingOrder)
        else:
            # 如果不是非首片,将信息显示在界面上去
            calcSize, cutboardSize, catchCenter01, catchCenter02 = self.get_cutboard_size_and_center()
            calcError = round(calcSize[0] - self.widthMm, 2), round(calcSize[1] - self.heightMm, 2)
            send_to_web_handler.show_not_first_cutline_in_web(self.cutLineRes.imgRes, calcSize, calcError,
                                                              cutboardSize, catchCenter01, catchCenter02)
            if self.buzzerIsOpen:
                self.cutPlc.set_buzzer_open_or_close(False)

        res = self.cutPlc.write_board_info(self.cutLineRes)
        debug_produce(res.info)
        self.cutPlc.result_is_ok()
        self.webModify = False
        self.isFirstBoard = False
        ds.workIndex += 1
        if ds.workIndex >= ds.indexMax:
            ds.workIndex = 1
        newData = {"workIndex": ds.workIndex, }
        db.update_data(TableName.workingInfos, {"key": "1"}, newData)
        ds.update_finished_val()

    @error_handler_produce
    def hand_label_boxes_1pin(self, boxInfo1) -> DataResult:
        """
        2拼板点击了标注
        """
        boxLeft = (np.array(boxInfo1[0]) * cp.sizeScale).astype('int').tolist()  # 转换为全部是int的列表
        if self.boardSizeAdjustFlag and self.isFirstBoard:
            self.widthMm = self.widthAdjustAfter
            self.heightMm = self.heightAdjustAfter
            self.widthPix = int(self.widthMm * cp.mm2pix)
            self.heightPix = int(self.heightMm * cp.mm2pix)
        boxLeft = self.get_box_rect_points(self.totalboard, boxLeft, boxInfo1[1])
        assert boxLeft is not None
        self.box1p = boxLeft
        cutResult: CutlineResult = get_cutlines_1p(self.lineImage, self.totalboardBox,
                                                   self.box1p, self.totalboardOffset, self.edgePixList)
        self.cutLineRes = cutResult
        show_cutline_in_web(cutResult.imgRes, cutResult.info)
        self.calcEndwith = "handLabel"
        debug_produce(f"id_{ds.workIndex} 界面点击了标注,识别信息:{cutResult.info}")
        return DataResult(state=True)

    @error_handler_produce
    def hand_inner_board_1pin_size_adjust(self, widthAdjust, heightAdjust) -> DataResult:
        """
        2拼板点击了宽度和高度调整
        """
        self.boardSizeAdjustFlag = True
        widthOriginal, heightOriginal = self.widthMm, self.heightMm
        widthOriginal += widthAdjust
        heightOriginal += heightAdjust
        self.widthAdjustAfter = widthOriginal
        self.heightAdjustAfter = heightOriginal
        widthPix = (self.widthAdjustAfter * cp.mm2pix)
        heightPix = (self.heightAdjustAfter * cp.mm2pix)
        lableSizePix = [int(widthPix / cp.sizeScale), int(heightPix / cp.sizeScale)]
        labelSizeMm = (self.widthAdjustAfter, self.heightAdjustAfter)
        send_to_web_handler.show_inner_board_hand_1pin(self.totalboard, lableSizePix,
                                                       labelSizeMm)
        return DataResult(state=True)

    @error_handler_produce
    def re_hand_label_from_web(self) -> DataResult:
        """
        界面上点击了重新标注
        :return:
        """
        debug_produce(f"id_{ds.workIndex} 界面点击了重新标注.")
        widthMm = self.widthAdjustAfter if self.boardSizeAdjustFlag else self.widthMm
        heightMm = self.heightAdjustAfter if self.boardSizeAdjustFlag else self.heightMm
        widthPix = int(self.widthMm * cp.mm2pix)
        heightPix = int(self.heightMm * cp.mm2pix)
        labelSizeMm = [widthMm, heightMm]
        labsizePix = [int(widthPix / cp.sizeScale), int(heightPix / cp.sizeScale)]
        send_to_web_handler.show_inner_board_hand_1pin(self.totalboard, labsizePix, labelSizeMm)
        return DataResult(state=True)

    @staticmethod
    def switch_screen_from_web():
        """
        界面上点击全屏切换,就是键盘F11
        :return:
        """
        keyboard.press_and_release("F11")

    def re_do_first_board_from_web(self) -> DataResult:
        """
        界面上点击了重新做首板
        :return:
        """
        debug_produce(f"id_{ds.workIndex} 界面点击了重新做首片,进行首片确认逻辑")
        self.isFirstBoard = True
        return DataResult(state=True)

    def after_edge_change_from_web(self, firstEdge, secondEdge, thirdEdge, forthEdge) -> DataResult:
        """
        界面上留边宽度进行了调整
        :return:
        """
        debug_produce(f"id_{ds.workIndex} 调整留边宽度: [{firstEdge}, {secondEdge}, {thirdEdge}, "
                      f"{forthEdge}]")
        edgePixList = [int(x * cp.mm2pix) for x in [firstEdge, secondEdge, thirdEdge, forthEdge]]
        self.cutLineRes: CutlineResult = get_cutlines_1p(self.lineImage, self.totalboardBox,
                                                         self.box1p, self.totalboardOffset, edgePixList)
        debug_produce(self.cutLineRes.info)
        self.webModify = True
        show_cutline_in_web(self.cutLineRes.imgRes, self.cutLineRes.info)
        return DataResult(state=True)

    def open_cutline_dir_from_web(self) -> DataResult:
        """
        界面上点击了打开切线图目录
        :return:
        """
        openDir = app_config.rawCutDir
        return open_dir(openDir)

    def open_first_board_cutline_dir_from_web(self) -> DataResult:
        """
        界面上点击了打开首件切线目录
        :return:
        """
        openDir = app_config.firstCutDir
        return open_dir(openDir)

    def open_log_dir_from_web(self) -> DataResult:
        """
        界面上点击了打开日志文件目录
        :return:
        """
        return open_dir(app_config.prodDebugDir)

    def change_order_from_web(self, key) -> DataResult:
        """
        请求更换工单,请求更换工单的时候,去加载一些参数,这里是手动更换工单,后面还需要批号
        """
        query = {
            "key": key
        }
        orderRes = db.get_data_one(TableName.orders, query)
        if not orderRes.state:
            return orderRes
        orderData = orderRes.data
        self.reload_order(orderData, isFirstBoard=True)
        send_to_web_handler.update_produce_model_in_web(ProduceDataType.workingOrder)
        return DataResult(state=True)
